export class Card {
  value: number;
  label: string;
  id: string;
  suit: string;
  weight: number;
  isArbitrary: boolean;
  constructor(value: number, suit: string,  isArbitrary: boolean = false) { 
    console.log('value', value, 'isArbitrary:', isArbitrary, 'suit:', suit)
    this.value = value;
    this.label = value === 1 ? 'A' : value === 11 ? 'J' : value === 12 ? 'Q' : value === 13 ? 'K' : value===14? 'Joker-black' : value === 15 ? 'Joker-red' :value.toString();
    this.suit = suit;
    this.weight = 1
    this.isArbitrary = isArbitrary;
    this.id = `${this.value}-${this.suit}`;
  }
}

export class CardsToUse {
  /**
   * cards: group of cards, length >= 2
   * value: range from 1 ~ 13 && 14 && 15
   * type: 2: 2 same cards, 3: 3 same cards, 4: 4 same cards, 5: 5 same cards; 6: 6same cards, 7: 7 same cards, 8: 8 same cards, 9: 3 with 2, 10: consistent 5 cards, 11: kings, 12: same suit color
   * weight: 1: common composition, 2: four same values, 3: 5 same values, 4: 6 same values, 5: 7 same values, 6: 8 same values, 7: kings, 8: consistent 5 same suit cards
   * */ 
  cards: Card[];
  value: number;
  type: number;
  weight: number;
  maxLen: number;
  constructor(cards: Card[]) {
    this.cards = cards.sort((a, b) => a.value - b.value)
    this.maxLen = 27
  }
  calculateWeight(): number {
    const len = this.cards.length;
    if (this.judgeIsLegal() === false) {
      return 0;
    }
    switch (len) {
     case 2 : {
      this.weight = this.type === 2 ? 1 : 7;
      break;
     }
     case 3 : {
      this.weight = 1;
      break;
     }
     case 4 : {
      let isSame = true;
      this.cards.forEach((card, index) => {
        if (index === 0) {
          return;
        } else if (card.value !== this.cards[0].value) {
            isSame = false;
        }
      })
      if (isSame) {
        this.weight = 2;
      } else {
        this.weight = 1;
      }
      
      break; 
     }
     case 5 : {
      this.weight = this.type === 5 ? 3 : this.type === 10 ? 1 : 8;
      break; 
     }
     case 6: {
      this.weight = 4
      break;
     }
     case 7: {
      this.weight = 5;
      break;
     }
     case 8: {
      this.weight = 6;
      break;
     }
    }
    return 0
  }
  setType():void {
    const len = this.cards.length;
    switch (len) {
      case 2 : {
        if (this.cards[0].value === this.cards[1].value) {
          this.type = 2;
        } else if (this.cards[0].value === 14 && this.cards[1].value === 15) {
          this.type = 11;
        }
        break;
      }
      case 3: {
        if (this.cards[0].value === this.cards[2].value) {
          this.type = 3;
        }
        break
      }
      case 4: {
        if (this.cards[0].value === this.cards[2].value || this.cards[1].value === this.cards[3].value) {
          this.type = 4;
        }
        break
      }
      case 5: {
        const first = this.cards[0].value;
        const last = this.cards[4].value;
        if (last - first === 4 && new Set(this.cards.map(c => c.value)).size === 5) {
          // consistent 5 cards
         this.type = this.cards[0].suit ===this.cards[1].suit && this.cards[0].suit === this.cards[2].suit && this.cards[0].suit === this.cards[3].suit &&  this.cards[0].suit === this.cards[4].suit ? 12 : 10
        } else if ((this.cards[0].value === this.cards[2].value && this.cards[3].value === this.cards[4].value) || (this.cards[0].value === this.cards[1].value && this.cards[2].value === this.cards[4].value)) {
          this.type = 9; 
        } else if (this.cards[0].value === this.cards[4].value) {
          this.type = 5 
        }
        break
      }
      case 6: {
        this.type = 6;
        break;
      }
      case 7: {
        this.type = 7;
        break;
      }
      case 8: {
        this.type = 8;
        break;
      }
    }
  }
  judgeIsLegal(): boolean {
    const len = this.cards.length;
    switch (len) {
      case 2 : {
        if (this.cards[0].value === this.cards[1].value || (this.cards[0].value === 14 && this.cards[1].value === 15)) {
          return true;
        }
        break;
      }
      case 3 : {
        if (this.cards[0].value === this.cards[1].value && this.cards[0].value === this.cards[2].value) {
          return true;
        }
        break;
      }
      case 4 : {
        if (this.cards[0].value === this.cards[2].value || this.cards[1].value === this.cards[3].value) {
          return true; 
        }
        break
      }
      case 5 : {
        const first = this.cards[0].value;
        const last = this.cards[4].value;
        return (last - first === 4 && 
               new Set(this.cards.map(c => c.value)).size === 5 )||
               (this.cards[0].value === this.cards[2].value && this.cards[3].value === this.cards[4].value )||
               (this.cards[0].value === this.cards[1].value && this.cards[2].value === this.cards[4].value)
      }
      case 6 : {
       return this.cards[0].value === this.cards[5].value 
      }
      case 7 : {
        return this.cards[0].value === this.cards[6].value 
      }
      case 8 : {
        return this.cards[0].value === this.cards[7].value 
      }
      default : {
        return false;
      }
    }
    return false;
  }
}

export class HandCard {
  cards: Card[];
  maxLen: number;
  constructor(cards: Card[]) {
    this.cards = cards;
    this.maxLen = 27;
  }
  judgeIsLegal(): boolean {
    return this.cards.length <= this.maxLen; 
  }
  getRestCards(cardsToUse: CardsToUse): Card[] {
    return this.cards.filter(item => cardsToUse.cards.filter(card => item.id === card.id).length === 0);
  }
}

export class Deck {
  cards: Card[];
  numRest: number;
  constructor(cards: Card[]) {
    this.cards = cards;
    this.numRest = this.cards.length;
  }
  drawCard() {
      this.numRest = this.numRest > 0 ? this.numRest - 1 : 0;
    return this.numRest > 0 ? this.cards.pop() : null
  }
}